package com.ld.control.business.sample.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ld.control.business.equipment.service.EquipmentService;
import com.ld.control.business.equipment.vo.resp.EquipmentDataFieldConfigRespVo;
import com.ld.control.business.equipment.vo.resp.EquipmentSampleFieldShowRespVo;
import com.ld.control.business.process.mapper.ProcessNodeExampleMapper;
import com.ld.control.business.process.mapper.ProcessNodeExampleRunningMapper;
import com.ld.control.business.process.model.ProcessExampleModel;
import com.ld.control.business.process.model.ProcessNodeExampleModel;
import com.ld.control.business.process.model.ProcessNodeExampleRunningModel;
import com.ld.control.business.process.service.ProcessExampleService;
import com.ld.control.business.sample.mapper.SampleMapper;
import com.ld.control.business.sample.model.SampleModel;
import com.ld.control.business.sample.service.SampleDataShowConfigService;
import com.ld.control.business.sample.service.SampleService;
import com.ld.control.business.sample.vo.resp.*;
import com.ld.control.common.vo.GenerateListVo;
import com.ld.control.common.vo.GeneratePageListVo;
import com.ld.control.exception.BusinessException;
import com.ld.control.utils.ExcelUtils;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 样品表，存放任务的样品信息 服务实现类
 * </p>
 *
 * @author wangfeng
 * @since 2024-06-12
 */
@Slf4j
@Service
public class SampleServiceImpl extends ServiceImpl<SampleMapper, SampleModel> implements SampleService {


    @Autowired
    private SampleMapper sampleMapper;

    @Autowired
    private ProcessNodeExampleRunningMapper processNodeExampleRunningMapper;

    @Autowired
    private EquipmentService equipmentService;

    @Autowired
    private ProcessExampleService processExampleService;

    @Autowired
    private ProcessNodeExampleMapper processNodeExampleMapper;

    @Autowired
    private SampleDataShowConfigService sampleDataShowConfigService;


    @Override
    public GeneratePageListVo<SampleExtRespVo> getPageList(Integer current, Integer size) {
        IPage<SampleExtRespVo> iPage = new Page<>(current, size);
        IPage<SampleExtRespVo> iPage1 = sampleMapper.selectAllGroupPageList(iPage);
        List<SampleExtRespVo> records = iPage1.getRecords();
        GenerateListVo<SampleDataShowConfigRespVo> sampleDataShowTitleList = sampleDataShowConfigService.getSampleDataShowTitleList();
        List<List<SampleDataRespVo>> sampleDataListList = List.of();
        for (SampleExtRespVo data : records) {
            sampleDataListList = new ArrayList<>();
            Long taskExampleId = data.getTaskExampleId();
            String barcode = data.getBarcode();
            for (SampleDataShowConfigRespVo configRespVo : sampleDataShowTitleList.getList()) {
                Long equipmentId = configRespVo.getEquipmentId();
                List<SampleDataRespVo> sampleDataList = getSampleDataList(taskExampleId, barcode, equipmentId);
                sampleDataListList.add(sampleDataList);
            }
            data.setSampleDataList(sampleDataListList);
        }
        return new GeneratePageListVo<>(iPage1);
    }

    private List<SampleDataRespVo> getSampleDataList(Long taskExampleId, String barcode, Long equipmentId) {
        List<SampleDataRespVo> sampleDataList = new ArrayList<>();

        List<SampleRespVo> sampleRespList = sampleMapper.selectByTaskExampleIdAndBarcodeAndEquipmentId(taskExampleId, barcode, equipmentId);
        List<EquipmentDataFieldConfigRespVo> EquipmentDataFieldConfigList = equipmentService.getEquipmentSampleFieldShowList(equipmentId);

        for (SampleRespVo data : sampleRespList) {
            String jsonData = data.getJsonData();
            if (ObjectUtils.isEmpty(jsonData)) {
                continue;
            }
            JSONObject jsonObject = JSONObject.parseObject(jsonData);
            SampleDataRespVo sampleDataRespVo;
            for (EquipmentDataFieldConfigRespVo configRespVo : EquipmentDataFieldConfigList) {
                sampleDataRespVo = new SampleDataRespVo();
                String fieldName = configRespVo.getFieldName();
                String fieldAlias = configRespVo.getFieldAlias();
                String fieldValue = jsonObject.getString(fieldName);
                sampleDataRespVo.setKey(fieldAlias);
                sampleDataRespVo.setValue(fieldValue == null ? "-" : fieldAlias + ":" + fieldValue);
                sampleDataList.add(sampleDataRespVo);
            }
        }
        return sampleDataList;
    }

    @Override
    public GeneratePageListVo<List<String>> getPageListExt1(Long taskExampleId, Long equipmentId, Integer current, Integer size) {
        Page<SampleRespVo> page = new Page<>(current, size);

        List<EquipmentDataFieldConfigRespVo> equipmentSampleFieldShowList = equipmentService.getEquipmentSampleFieldShowList(equipmentId);
        IPage<SampleRespVo> sampleRespVoIPage = sampleMapper.selectListByCondition(page, taskExampleId, equipmentId);
        List<SampleRespVo> records = sampleRespVoIPage.getRecords();

        List<List<String>> dataList = new ArrayList<>();
        IPage<List<String>> sampleRespVoPage = new Page<>();
        BeanUtils.copyProperties(sampleRespVoIPage, sampleRespVoPage);
        if (!ObjectUtils.isEmpty(records)) {
            for (SampleRespVo record : records) {
                String jsonData = record.getJsonData();
                if (ObjectUtils.isEmpty(jsonData)) {
                    continue;
                }
                List<String> valueList = new ArrayList<>();
                JSONObject jsonObject = JSONObject.parseObject(jsonData);
                for (EquipmentDataFieldConfigRespVo filedName : equipmentSampleFieldShowList) {
                    String value = jsonObject.getString(filedName.getFieldName());
                    valueList.add(value);
                }
                dataList.add(valueList);
            }
        }
        sampleRespVoPage.setRecords(dataList);
        return new GeneratePageListVo<>(sampleRespVoPage);
    }

    @Override
    public void downloadSampleData(HttpServletResponse response, Long taskExampleId, Long equipmentId) {
        List<EquipmentDataFieldConfigRespVo> equipmentSampleFieldShowList = equipmentService.getEquipmentSampleFieldShowList(equipmentId);
        // excel标题
        List<String> titleList = equipmentSampleFieldShowList.stream().map(EquipmentDataFieldConfigRespVo::getFieldAlias).collect(Collectors.toList());
        // 数据生成
        GeneratePageListVo<List<String>> dataPage = getPageListExt1(taskExampleId, equipmentId, 1, 9999);
        List<List<String>> dataList = dataPage.getList();
        String filePath = ExcelUtils.generateExcel(titleList, dataList);
        File file = new File(filePath);
        if (!file.exists()) {
            throw new BusinessException("当前下载的文件不存在，请检查路径是否正确");
        }

        // 将文件写入输入流
        try (InputStream is = new BufferedInputStream(Files.newInputStream(file.toPath()))) {

            // 一次性读取到内存中
            byte[] buffer = new byte[is.available()];
            int read = is.read(buffer);

            // 清空 response
            response.reset();
            response.setCharacterEncoding("UTF-8");

            // Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
            // attachment表示以附件方式下载   inline表示在线打开   "Content-Disposition: inline; filename=文件名.mp3"
            // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));

            // 告知浏览器文件的大小
            response.addHeader("Content-Length", "" + file.length());

            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            outputStream.write(buffer);
            outputStream.flush();
            outputStream.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void callBackSample(Long processNodeExampleModelId) {
        ProcessNodeExampleModel processNodeExampleModel1 = processNodeExampleMapper.selectById(processNodeExampleModelId);
        ProcessExampleModel processExampleModel = processExampleService.getById(processNodeExampleModel1.getProcessExampleId());
        Long taskExampleId = processExampleModel.getTaskExampleId();
        try {
            Thread.sleep(1000);
            log.info("callBackSample, taskExampleId: {}", taskExampleId);
            QueryWrapper<ProcessNodeExampleRunningModel> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(ProcessNodeExampleRunningModel.TASK_EXAMPLE_ID, taskExampleId);
            queryWrapper.eq(ProcessNodeExampleRunningModel.PROCESS_NODE_EXAMPLE_ID, processNodeExampleModelId);
            List<ProcessNodeExampleRunningModel> processNodeExampleRunningModelList = processNodeExampleRunningMapper.selectList(queryWrapper);
            List<Object> sampleDataList = getSampleData(processNodeExampleRunningModelList);
            log.info("SampleDataRespVo:{}", sampleDataList);
            for (Object sampleDataObj : sampleDataList) {
                String jsonData = JSONObject.toJSONString(sampleDataObj);
                log.info("callBackSample jsonData:{}", jsonData);
                JSONObject jsonObject = JSONObject.parseObject(jsonData);
                String code = jsonObject.getString("sysBarcode");
                addSample(jsonData, code, processNodeExampleRunningModelList.get(0));
            }
        } catch (Exception e) {
            log.error("callBackSample error, taskExampleId: {}", taskExampleId, e);
        }

    }

    @Override
    public List<SampleDataFileRespVo> getSampleDataFileList(Long taskExampleId) {
        List<SampleDataFileRespVo> sampleDataFileRespVoList = new ArrayList<>();

        SampleDataFileRespVo sampleDataFileRespVo1 = new SampleDataFileRespVo();
        sampleDataFileRespVo1.setId(1L);
        sampleDataFileRespVo1.setFileName("总磷总氮检测报告.pdf");
        sampleDataFileRespVo1.setFileDownloadUrl("http://ldtest001.natapp1.cc/ldbucket-uat/space1/20240912/9cff373be1d9453b897075c6179583e7_1726106303927.pdf");
        sampleDataFileRespVoList.add(sampleDataFileRespVo1);

        SampleDataFileRespVo sampleDataFileRespVo2 = new SampleDataFileRespVo();
        sampleDataFileRespVo2.setId(2L);
        sampleDataFileRespVo2.setFileName("总磷总氮检测报告.xls");
        sampleDataFileRespVo2.setFileDownloadUrl("http://ldtest001.natapp1.cc/ldbucket-uat/space1/20240912/b68cdcdca06849f2b91f113117fc4ad4_1726106392450.xls");
        sampleDataFileRespVoList.add(sampleDataFileRespVo2);

        return sampleDataFileRespVoList;
    }

    private void addSample(String jsonData, String code, ProcessNodeExampleRunningModel runningModel) {
        SampleModel sampleModel = new SampleModel();
        sampleModel.setTaskExampleId(runningModel.getTaskExampleId());
        sampleModel.setSubTaskExampleId(runningModel.getSubTaskExampleId());
        sampleModel.setProcessExampleId(runningModel.getProcessExampleId());
        sampleModel.setProcessNodeExampleId(runningModel.getProcessNodeExampleId());
        sampleModel.setProcessNodeExampleRunningId(runningModel.getId());
        sampleModel.setEquipmentId(runningModel.getEquipmentId());
        sampleModel.setBarcode(code);
        sampleModel.setCreateTime(new Date());
        sampleModel.setJsonData(jsonData);
        sampleMapper.insert(sampleModel);
    }

    private List<Object> getSampleData(List<ProcessNodeExampleRunningModel> processNodeExampleRunningModelList) {
        List<Object> resultDataList = new ArrayList<>();
        for (ProcessNodeExampleRunningModel runningModel : processNodeExampleRunningModelList) {
            String sendMethodName = runningModel.getSendMethodName();
            if ("GetLastDatas".equals(sendMethodName) || "RunMethod".equals(sendMethodName) || sendMethodName.endsWith("RunMethod")) {
                String responseResult = runningModel.getResponseResult();
                JSONObject jsonObject = JSONObject.parseObject(responseResult);
                String data = jsonObject.getString("equipmentDataList");
                // 兼容一下老版本数据获取
                if (ObjectUtils.isEmpty(data)) {
                    data = jsonObject.getString("Result");
                }
                List<Object> dataList = JSONObject.parseArray(data);
                resultDataList.addAll(dataList);
            }
        }
        return resultDataList;
    }
}